Godot 4.x Tween機能練習場所
参考ページ
1秒かけてマウスクリックした箇所に移動する
code:gd
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.is_pressed():
move_to_mouse()
func move_to_mouse() -> void:
var tween := create_tween()
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
完了後に print文出力
tween.tween_callback(func(): print("test"))
tween_callback() の引数は、callable 型を受け取るので、ラムダ式で渡すか既存関数への参照を渡す
マウスクリックした箇所に移動後に、巨大化
https://gyazo.com/ab0a907caf8795fe58a14f9cc67d05b5
code:gd
var tween := create_tween()
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_property(self, "scale", Vector2.ONE*2, 0.5)
普通に連続して tween_property を書くと、連続実行になる
マウスクリックした箇所に移動しながら巨大化(並列実行)
https://gyazo.com/2be0e05a9649e8d3e4bbdebd59201f49
code:gd
var tween := create_tween()
tween.set_parallel(true)
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_property(self, "scale", Vector2.ONE*2, 1.5)
tween.set_parallel(true) でその tween は並列実行になる
もしくは、tween.parallel()を呼び出すと、次の操作だけ並列実行にできる。その次はまた連続実行になる。
code:gd
var tween := create_tween()
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.parallel()
tween.tween_property(self, "scale", Vector2.ONE*2, 1)
tween.tween_property(self, "rotation", PI, 1)
上記の場合、"global_position"の移動と"scale"の変化は並列に実行されるが、"rotation" の変化はその後 serial 実行される
EASE typeと TRANS type を指定
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween 間に待機時間を追加
code:gd
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_interval(1)
tween.tween_property(self, "scale", Vector2.ONE*2, 1)
tween_interval() を挟むと、引数の秒数だけ待機してから後続の tween が実行される
1つのプロパティに対して2つ以上のTweenで操作しないこと。ドキュメントに以下の記述がある。
You should avoid using more than one Tween per object's property. If two or more tweens animate one property at the same time, the last one created will take priority and assign the final value. If you want to interrupt and restart an animation, consider assigning the Tween to a variable:
2つ以上Tweenが1つのプロパティを同時に操作する場合、最後に生成されたtween が採用される
実際に以下のコードでは、最後のtween3 の挙動だけが実行される
code:gd
var tween := create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
var tween2 := create_tween()
tween2.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween2.tween_property(self, "global_position", Vector2.ZERO, 1.0)
var tween3 := create_tween()
tween3.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween3.tween_property(self, "global_position", Vector2.ONE * 100, 1.0)
ただし、tween3 に interval を設定すると、tween2 が実行された後に tween3 が実行される。
ループさせる
tween.set_loop(int x)で x回ループさせる
0にすると無限ループする
以下は無限に拡大縮小を繰り返す Tween
code:gd
tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.set_loops(0)
tween.tween_property(self, "scale", Vector2(1.5,1.5), 0.5)
tween.tween_property(self, "scale", Vector2(0.4,0.4), 0.5)
Tweenの終了などを検知する
finished Signal で終了を検知できる
以下のコードでは、Tween終了後に "move_finished" を出力する
code:gd
tween = create_tween()
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.finished.connect(move_finish)
func move_finish() -> void:
print("move_finished!")
tween_callbackの方が先に実行される。以下のコードでは、"tween callback" が先に出力される。
code:gd
tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.finished.connect(move_finish)
tween.tween_callback(func():print("tween_callback!"))
func move_finish() -> void:
print("move_finished!")
tween_callback に set_delay(1)で delay させた場合、1秒後に "tween callback" が出力されてから、"move_finished" が出力される。
tween.tween_callback(func():print("tween_callback!")).set_delay(1)
finished シグナルは、set_delay も完了しないと 発行されないようだ
finished シグナルの他には、loop_finishedシグナルと step_finished シグナルがある。
loop_finished は、複数回ループがある場合にループ終了後に発行される
step_finished は、1つのステップ終了後(パラレルでまとめれた場合はそのまとめられた単位で1ステップ)に発行される
以下のコードを実行すると
code:gd
tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.set_loops(3)
tween.step_finished.connect(func(x):print("step finished: idx=" + str(x)))
tween.loop_finished.connect(func(x):print("loop finished: loop count = " + str(x)))
tween.finished.connect(func():print("tween finished"))
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_method(output_num,1, 10, 0.5)
コンソールには以下の様に出力される
code:txt
step finished: idx=0
step finished: idx=1
loop finished: loop count = 1
step finished: idx=0
step finished: idx=1
loop finished: loop count = 2
step finished: idx=0
step finished: idx=1
tween finished
tween_methods
tween_methods は、第1引数に渡した callable を from - to で連続実行させる機能
以下のコードでは、2秒間で、1 ~ 10 の整数値を渡して output_num関数を実行している
型を float にすれば、整数じゃなくてもok.
code:gd
tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.set_parallel(true)
tween.tween_property(self, "global_position", get_global_mouse_position(), 2.0)
tween.tween_method(output_num,1, 10, 2)
func output_num(num: int) -> void:
$Label.text = "num:" + str(num)
https://gyazo.com/064222aefcbbd8860553f1860d3402d4
custom_step で指定秒後の状態に即座に遷移
bool custom_step ( float delta )で、 delta 秒後の状態に即座に遷移する
まだ Tween animation が残っている場合は true が返ってくる
大きな delta を渡すと、即座に終了状態に遷移する
以下のコードでは、1秒後のマウスクリックした場所に移動するTweenの0.5秒後の状態に遷移する ≒ マウスクリック座標との中間地点にワープする動きになる
code:gd
tween = create_tween()
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_method(output_num,1, 10, 0.5)
tween.stop()
tween.custom_step(0.5)
https://gyazo.com/71b34c084d350da9ffd0eede3773a79e
Tweenの状態チェック関数と、再生・停止・終了処理の関係
状態チェック関数は以下の2つがある
$ is_running()
Returns whether the Tween is currently running, i.e. it wasn't paused and it's not finished.
実行中かどうか。pause されておらず、まだ finish していないこと
$ is_valid()
Returns whether the Tween is valid. A valid Tween is a Tween contained by the scene tree (i.e. the array from SceneTree.get_processed_tweens will contain this Tween). A Tween might become invalid when it has finished tweening, is killed, or when created with Tween.new(). Invalid Tweens can't have Tweeners appended.
こっちはやや複雑で、有効な tween かどうかの判定
無効になる条件は、既に fnished になっていたり、kill されていたり、Tween.new() で生成されていたり
無効になっている Tween は Tweeners を追加できない
状態変更処理は以下の4つがある
$ play()
Resumes a paused or stopped Tween.
再開する
$ stop()
Stops the tweening and resets the Tween to its initial state. This will not remove any appended Tweeners.
停止して、Tween を初期状態に戻す
Tweeners を削除されず、play でまた最初から再開できる
$ pause()
Pauses the tweening. The animation can be resumed by using play.
一時停止する。play で再開可能
$ kill()
Aborts all tweening operations and invalidates the Tween.
無効化する
色々試してみた
code:gd
func move_to_mouse() -> void:
tween = create_tween()
_tween_state_check(tween, 1)
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_QUART)
tween.tween_property(self, "global_position", get_global_mouse_position(), 1.0)
tween.tween_method(output_num,1, 10, 0.5)
tween.tween_callback(_tween_state_check.bindv(tween,2)) # tween.finished.connect(_tween_state_check.bindv(tween, 3)) tween.finished.connect(_tween_kill_and_state_check.bindv(tween, 3)) await get_tree().create_timer(7.0).timeout
_tween_state_check(tween, 4)
func _tween_state_check(tween: Tween, index: int):
if tween.is_running():
print(str(index) + ": tween is running")
if tween.is_valid():
print(str(index) + ": tween is valid")
func _tween_kill_and_state_check(tween: Tween, index: int):
tween.kill()
_tween_state_check(tween, index)
出力
code:txt
1: tween is running
1: tween is valid
2: tween is running
2: tween is valid
3: tween is valid
分かったこと
tween_callback 時にはまだ running && valid
finished シグナル発行後は、runnning ではなくなっているが、まだ valid
tween.kill() 呼び出し直後は、まだ valid
数秒後には、valid でもなくなっている
tween.kill() を呼ばなくても、数秒後に valid ではなくなっていた